﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Net;
using System.Net.Sockets;

public struct Userdata
{
    public int id;
    public byte[] dataInfo;
}

namespace WuHouCiClient
{
    
    class CProtocol
    {
        private Queue<byte> recvBuffer;//用于存放未处理的收到的信息
        private Queue<byte> sendBuffer;//用于存放序列化之后的发送信息.
        private Queue<Userdata> recvListInfo;//用于存放接收到的信息.
        private Queue<Userdata> sendListInfo;//用于存放发送的信息。
        private TcpClient tcpClietnt = null;
        //-----------------------------------
        int protocolStart = -101;
        int protocolEnd = -111;
        Int64 entryKey = 1314520;

        //------------对CProtocol进行单列处理，在一个客户端中只会有一个单列来统一处理所有的消息
        private static CProtocol cProtocol = null;
        public static CProtocol getInstance(TcpClient client)
        {
            if (cProtocol == null)
            {
                cProtocol = CProtocol.create(client);
                return cProtocol;
            }
            else
            {
                return cProtocol;
            }
        }
        public static CProtocol create(TcpClient client)
        {
            cProtocol = new CProtocol();
            cProtocol.init(client);
            return cProtocol;
        }
        //初始化
        private void init(TcpClient tcpClietnt)
        {
            recvBuffer = new Queue<byte>();
            recvBuffer.Clear();
            sendBuffer = new Queue<byte>();
            sendBuffer.Clear();
            recvListInfo = new Queue<Userdata>();
            recvListInfo.Clear();
            sendListInfo = new Queue<Userdata>();
            sendListInfo.Clear();
            this.tcpClietnt = tcpClietnt;
        }
        //向recvbuffer中放入值。
        public bool pushRecvBuffer(byte[] message)
        {

            for(int i = 0; i < message.Length; i++)
            {
                   //解密
                recvBuffer.Enqueue(message[i]);
            }
            this.update(1);
            return true;
        }
        //向send buffer中放入值
        private bool pushSendBuffer(byte[] message)
        {
            for (int i = 0; i < message.Length; i++)
            {
                sendBuffer.Enqueue(message[i]);
            }
            return true;
        }

        //在向接收缓存和发送缓存中放入数据时，进行更新.
        private bool update(int sendto) //1发送到客户端，2发送到服务器
        {
            
            //发送给服务器数据，或者发送给客户端存根代码。
            if (sendto == 1)
            {
                this.recvBufferToInfoList();
                this.sendToClient();
            }
            else
            {
                CNet.sendPakage(sendBuffer.ToArray(),this.tcpClietnt); //发送包
                sendBuffer.Clear();//清除数据.
            }
            return true;
        }
        //向服务器发送消息,由客户端调用
        public bool sendToServer(Userdata d)
        {
            this.sendListInfo.Enqueue(d);//将发送的数据放到 sendListInfo中
            this.sendListInfoToBuffer();//对sendListInfo中的数据加密加协议
            this.update(2);
            return true;
        }
        //向本地客户端发送消息
        private bool sendToClient()
        {
            if (recvListInfo.Count > 0)
            {
                for (int i = 0; i < recvListInfo.Count;i++ )
                {
                    CNet net = CNet.getInstance();
                    Userdata d = recvListInfo.Dequeue();//删除消息
                    net.recvPulicFunction(d); //发送到客户端
                }
            }
            return true;
        }
        //将收到的信息解协议处理，放到recvListInfo中
        private void recvBufferToInfoList()
        {
            
            //解协议
            byte[] proStart = CProtocol.intToByte4(protocolStart);
            byte[] proEnd = CProtocol.intToByte4(protocolEnd);
            //检索字符串
            byte[] recv = recvBuffer.ToArray();
            int index = KMP(recv, proStart);
            if (index == -1)
            {
                recvBuffer.Clear();
            }
            else
            {
                for (int i = 0; i < index; i++)
                {
                    recvBuffer.Dequeue();
                }
            }
            recv = recvBuffer.ToArray();
            index = KMP(recv, proEnd);
            if (index != -1)
            {
                byte[] idBytes = new byte[4];
                for (int i = 0; i < 4; i++)
                {
                    recvBuffer.Dequeue();
                }
                for (int i = 0; i < 4; i++)
                {
                    idBytes[i] = recvBuffer.Dequeue();
                }
                Userdata d = new Userdata();
                d.id = byte4ToInt(idBytes);
                byte[] dInfo = new byte[index- 8];
                for (int i = 0; i < index- 8;i++ )
                {
                    dInfo[i] = recvBuffer.Dequeue();
                }
                for (int i = 0; i < 4; i++)
                {
                    recvBuffer.Dequeue();
                }
                d.dataInfo = dInfo;
                recvListInfo.Enqueue(d);
            }
        }
        //将sendListInfo的信息，加协议，加密处理，放到sendBuffer中
        private byte[] sendListInfoToBuffer()
        {
            if (sendListInfo.Count > 0)
            {
                foreach(Userdata d in sendListInfo)
                {
                    byte[] proStart = CProtocol.intToByte4(protocolStart);
      
                    byte[] id = CProtocol.intToByte4(d.id);

                    byte[] proEnd = CProtocol.intToByte4(protocolEnd);
                       //将byte[]数组连接起来。
                    List<byte> list = new List<byte>();
                    list.AddRange(proStart);
                    list.AddRange(id);
                    list.AddRange(d.dataInfo);
                    list.AddRange(proEnd);
                    byte[] comByte = list.ToArray();
                    //加密
                    // 放到buffer中
                    pushSendBuffer(comByte);
                }
            }
           
            return null;
        }


        //将int 转成byte[4]
        public static byte[] intToByte4(Int32 n)
        {
            byte[] number = new byte[4];
            number[0] = (byte)(n);
            number[1] = (byte)(n >> 8);
            number[2] = (byte)(n >> 16);
            number[3] = (byte)(n >> 24);
            return number;
        }
        //将byte[4] 转换成int
        public static int byte4ToInt(byte[] b)
        {
            int number = 0;
            number = b[0] | b[1] << 8 | b[2] << 16 | b[3]<<24;
            return number;
        }

        //将string类型转换成byte[]
        public static byte[] stringToByte(string source)
        {
            return Encoding.UTF8.GetBytes(source);
        }

        //将byte[] 转换成string
        public static string byteToString(byte[] source)
        {
            return Encoding.UTF8.GetString(source);
        }


















        //在byte[] 中查找一个byte[]
       public static int KMP(byte[] zstr, byte[] mstr)
        {
            int i, j;
            int[] next = new int[mstr.Length];
            GetNextVal(mstr, next);
            i = 0;
            j = 0;
            while (i < zstr.Length && j < mstr.Length)
            {
                if (j == -1 || zstr[i] == mstr[j])
                {
                    ++i;
                    ++j;
                }
                else
                {
                    j = next[j];
                }
            }
            if (j == mstr.Length)
                return i - mstr.Length;
            return -1;
        }
        //next 函数
       public static void GetNextVal(byte[] str, int[] next)
        {
            int i = 0;
            int j = -1;
            next[0] = -1;
            while (i < str.Length - 1)
            {
                if (j == -1 || str[i] == str[j])
                {
                    i++;
                    j++;
                    next[i] = j;
                }
                else
                {
                    j = next[j];
                }
            }
        }
        //获取recvlist
       // public 
    }
}
